
// #include <iostream>
// #include <pthread.h>
// #include <queue>
// #include <functional>

// // 基于阻塞队列的单生产者单消费者模型实现

// const int dfaultcap = 5;

// // 当任务是一个函数
// using func_t = std::function<void()>;

// void downLoad()
// {
//     std::cout << "这是一个下载任务" << std::endl;
// }
// template <typename T>
// class blockQueue
// {
// private:
//     bool isFull()
//     {
//         return _q.size() >= _cap;
//     }
//     bool isEmpty()
//     {
//         return _q.empty();
//     }

// public:
//     blockQueue(int cap = dfaultcap, int cSleepCnt = 0, int pSleepCnt = 0)
//         : _cap(cap), _cSleepCnt(cSleepCnt), _pSleepCnt(pSleepCnt)
//     {
//         pthread_mutex_init(&_mutex, nullptr);
//         pthread_cond_init(&_fullCond, nullptr);
//         pthread_cond_init(&_emptyCond, nullptr);
//     }
//     void Equeue(T &data)
//     {
//         pthread_mutex_lock(&_mutex);
//         // if(isFull())
//         while (isFull())
//         {
//             _pSleepCnt++;
//             std::cout << "生产者等待..." << std::endl;
//             // 等待成功需要释放锁
//             // 那么被唤醒之后要重新在该地方申请锁
//             // 要是申请失败那么就要在锁上面等待
//             pthread_cond_wait(&_fullCond, &_mutex);
//             // pthread_cond_wait是一个函数调用 可能失败 也就是此时不会成功等待 在队列为满的情况下会插入数据
//             // 可能在这个线程被唤醒之前 已经有生产者被唤醒了 此时队列又满了 这称为伪唤醒 那么就不能插入数据
//             // 解决这个问题只需要让这个等待循环执行 这样满了就会一直等待 只到不满出去循环合法插入数据
//             _pSleepCnt--;
//         }
//         _q.push(data);
//         // 唤醒方式一
//         if (_cSleepCnt > 0)
//         {
//             std::cout << "消费者被唤醒" << std::endl;
//             pthread_cond_signal(&_emptyCond);
//         }
//         // 唤醒方式二
//         // 就算被唤醒的对象没有等待 接收到唤醒信号也不影响 所以可以直接signal
//         // pthread_cond_signal(&_emptyCond);
//         // 放到unlock前面因为这边的锁还没有释放 所以另一边一定会申请锁失败 但是不影响 这边代码会继续向后走
//         // 会释放锁 另一边就可以申请到锁了
//         pthread_mutex_unlock(&_mutex);
//         // pthread_cond_signal(&_emptyCond);
//         //  放到unlock后面没有问题 这两种都行
//     }
//     T Pop()
//     {
//         pthread_mutex_lock(&_mutex);
//         // if(isEmpty())
//         while (isEmpty())
//         {
//             _cSleepCnt++;
//             std::cout << "消费者等待..." << "_cSleepCnt: "<< _cSleepCnt << std::endl;

//             pthread_cond_wait(&_emptyCond, &_mutex);
//             _cSleepCnt--;
//         }
//         T data = _q.front();
//         _q.pop();
//         if (_pSleepCnt > 0)
//         {
//             std::cout << "生产者被唤醒" << std::endl;
//             pthread_cond_signal(&_fullCond);
//         }
//         // pthread_cond_signal(&_fullCond);
//         pthread_mutex_unlock(&_mutex);
//         // pthread_cond_signal(&_fullCond);

//         return data;
//     }
//     ~blockQueue()
//     {
//         pthread_mutex_destroy(&_mutex);
//         pthread_cond_destroy(&_fullCond);
//         pthread_cond_destroy(&_emptyCond);
//     }

// private:
//     std::queue<T> _q;
//     int _cap;
//     pthread_mutex_t _mutex;
//     pthread_cond_t _fullCond;
//     pthread_cond_t _emptyCond;

//     int _cSleepCnt;
//     int _pSleepCnt;
// };


// 使用自己封装的锁和条件变量

#include <iostream>
#include <pthread.h>
#include <queue>
#include <functional>

#include "mutexEncapsulation.hpp"
using namespace MutexModule;

#include "condEncapsulation.hpp"
using namespace CondModule;


// 基于阻塞队列的单生产者单消费者模型实现

const int dfaultcap = 5;

// 当任务是一个函数
using func_t = std::function<void()>;

void downLoad()
{
    std::cout << "这是一个下载任务" << std::endl;
}
template <typename T>
class blockQueue
{
private:
    bool isFull()
    {
        return _q.size() >= _cap;
    }
    bool isEmpty()
    {
        return _q.empty();
    }

public:
    blockQueue(int cap = dfaultcap, int cSleepCnt = 0, int pSleepCnt = 0)
        : _cap(cap), _cSleepCnt(cSleepCnt), _pSleepCnt(pSleepCnt)
    {
    }
    void Equeue(T &data)
    {
        LockGuard lockguard(&_mutex);
        while (isFull())
        {
            _pSleepCnt++;
            std::cout << "生产者等待..." << std::endl;
            _fullCond.Wait(_mutex);
            _pSleepCnt--;
        }
        _q.push(data);
        if (_cSleepCnt > 0)
        {
            std::cout << "消费者被唤醒" << std::endl;
            _emptyCond.Signal();
        }
    }
    T Pop()
    {
        LockGuard lockguard(&_mutex);
        while (isEmpty())
        {
            _cSleepCnt++;
            std::cout << "消费者等待..." << "_cSleepCnt: "<< _cSleepCnt << std::endl;
            _emptyCond.Wait(_mutex);
            _cSleepCnt--;
        }
        T data = _q.front();
        _q.pop();
        if (_pSleepCnt > 0)
        {
            std::cout << "生产者被唤醒" << std::endl;
            _fullCond.Signal();
        }
        return data;
    }
    ~blockQueue()
    {
    }

private:
    std::queue<T> _q;
    int _cap;
    Mutex _mutex;
    Cond _fullCond;
    Cond _emptyCond;

    int _cSleepCnt;
    int _pSleepCnt;
};